#define _GNU_SOURCE
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
#include <glib.h>
#include <glib/gprintf.h>
#include <stdbool.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

/*gcc -g -Wall `pkg-config --cflags glib-2.0` -c commandes.c -o commandes.o*/
int attente_fils(int pid) {
  
  int status;
  pid_t res;

  res = waitpid(pid, &status, 0);

  if (res < 0) {
    if (errno == 10) {
      return 1;
    }

    fprintf(stderr, "erreur avec le waitpid %s\n", strerror(errno));
    exit(1);
  }

  if (WIFEXITED(status)) {
    fprintf(stdout, "la commande s'est terminÃ©e en renvoyant %d\n", WEXITSTATUS(status));
    return 1;
  }
  
  if (WIFSIGNALED(status)) {
    fprintf(stdout, "la commande s'est terminÃ©e suite au signal %d\n", WTERMSIG(status));
    return 1;
  }
  
  if (WIFSTOPPED(status)) {
    fprintf(stdout, "la commande Ã  Ã©tÃ© stoppÃ©e par le signal %d\n", WSTOPSIG(status));
    return 0;
  }
  
  if (WIFCONTINUED(status)) {
    fprintf(stdout, "la commande Ã  Ã©tÃ© relancÃ©e\n");
    return 0;
  }

  fprintf(stdout, "ceci ne devrait pas arriver\n");
  exit(1);
}


void     traitement_signal_fils (int sig, siginfo_t *info, void *ingore) {
  int res;


  
  res = attente_fils(info->si_pid);
  if (res != 1) {
    
    fprintf(stderr, "Ceci ne devrait pas arriver\n");
    exit(1);
  }

}

int executevp(const char *file, char *const argv[]) {
  char *const *pt;
  fprintf(stdout, "Le shell doit Ã©xÃ©cuter la commande %s avec les arguments :#", file);
    
  pt = argv;
  while (*pt != NULL) {
    fprintf(stdout, "%s## ",*pt);
    pt++;
  }
  fprintf(stdout, "\n");
  return 0;
}


int main(int argc, char *argv[]) {
  
  struct sigaction sa;
  sigaction(SIGCHLD, NULL, &sa);
  sa.sa_flags = SA_SIGINFO|SA_NOCLDSTOP|SA_RESTART;
  sa.sa_sigaction = traitement_signal_fils;
  
  sigaction(SIGCHLD, &sa, NULL);

  while (1) {
    int attend;
    char **tab_com_pipe = NULL;
    char **arg_com1 = NULL;
    char **arg_com2 = NULL;
    char *text_com = NULL;
    size_t taille_com = 0;
    ssize_t res;

   
    fprintf(stdout, "entrez une commande>");
    fflush(stdout);

    res = getline(&text_com, &taille_com, stdin);
    if (res < 0) {
      perror("problÃ¨me de lecture sur la ligne de commande");
      exit(1);
    }
    if (text_com != NULL) {

      g_strdelimit(text_com, "\t\n", ' ');
      g_strstrip(text_com);

      fprintf(stderr, "lecture de la commande \"%s\"\n", text_com);
      if (strcmp(text_com, "fin")==0) {

	fprintf(stderr, "bye\n");
	free(text_com);
	break;
      }

      if (strlen(text_com) == 0) {
	
	fprintf(stderr, "La comande est vide\n");
	free(text_com);
	continue;
      }
      
      if (text_com[strlen(text_com)-1] == '&') {
	
	attend = false;
	text_com[strlen(text_com)-1] = '\0';
	g_strstrip(text_com);
      } else {
	
	attend = true;
      }
      
      tab_com_pipe = g_strsplit(text_com, "|", -1);
      
      
      if (g_strv_length(tab_com_pipe) == 1) {
	pid_t pid_com;
  
	
	arg_com1 = g_strsplit_set(tab_com_pipe[0], "\t ", -1);

	
	pid_com = fork();
	if (pid_com < 0) {
	  perror("Il y a eu un problÃ¨me durant le fork()");
	  exit(1);
	}
	if (pid_com == 0) {
	  fprintf(stderr, "lancement de %s\n", text_com);
	  execvp(arg_com1[0], arg_com1);
	  fprintf(stderr, "erreur avec la commande %s car : %s\n", text_com, strerror(errno));
	  exit(2);
	} else {

	  if (attend) {
	    attente_fils(pid_com);
	  } else {
 
	    
	  }
	}
	

      }
      else if (g_strv_length(tab_com_pipe) == 2) {
	
	g_strstrip(tab_com_pipe[0]);
	g_strstrip(tab_com_pipe[1]);
	
	arg_com1 = g_strsplit_set(tab_com_pipe[0], "\t ", -1);
	arg_com2 = g_strsplit_set(tab_com_pipe[1], "\t ", -1);
	
	fprintf(stdout, "Dont la sortie est redirigÃ©e vers\n");
	executevp(arg_com2[0], arg_com2);

	if (attend) {
	  fprintf(stdout, "Au premier plan\n");
	} else {
	  fprintf(stdout, "En tache de fond\n");	  
	}	
	
      } else {
	fprintf(stderr, "Je ne sais pas faire Ã§a\n");
	exit(1);
      }
      

      if (tab_com_pipe != NULL) {
	g_strfreev(tab_com_pipe);
      }
      if (arg_com1 != NULL) {
	g_strfreev(arg_com1);
      }
      if (arg_com2 != NULL) {
	g_strfreev(arg_com2);
      }
      if (text_com != NULL) {
	free(text_com);
      }
    }
    
    
  }   

  return 0;
}


